眼看就要進入尾聲了,今天就來講如何從資料庫撈資料吧!使用的語言就是Language-Integrated Query (LINQ),LINQ除了可以針對entity查詢之外,也可以針對object或xml來查詢,今天就直接針對LINQ to Entities來做說明,最後再補充導覽屬性的應用
LINQ to Entities 的查詢提供兩種語法:
使用Scaffold產生的程式碼,預設都是使用『以方法為基礎的查詢語法』方式來做CURD,直接看Code:
必須先建立DbContext才能以物件的方式查詢entity,如下圖的UserEntities1繼承DbContext
Update(修改User),使用Entry()方法並搭配db.SaveChanges()方法
Delete(刪除User),使用Remove()方法並搭配db.SaveChanges()方法
而在昨天改寫Scaffold產生的程式碼以符合顯示多筆Email資訊的功能,也有使用到Where()方法,其中的d => d.UserID == id就是Lambda 運算式
在之前View裡面使用html helper時搭配For結果的方法也時常使用到Lambda 運算式,使用方式如下:
自訂義參數名稱 => 自訂義參數名稱.物件屬性
另外還有很多時常用到的方法,例如:Select()、OrderBy()、Take()與Skip()等等,在初學的時候其實都是邊開發專案邊查詢,相關的使用範例可以看這個網站101 LINQ Samples
再來看另外一種
將昨天透過方法取得資料庫資料的程式碼改寫成「查詢運算式語法」,如下圖39行,跟SQL很類似都是搭配from、where或select這些關鍵字來組成查詢語法,這邊我自己剛開始學習時非常難適應,因為我DB那塊就是弱到爆炸,所以反而很喜歡透過方法查詢的方式,可以透過方法或以物件導向的觀念直接跟DbContext溝通,不過在特殊情況「查詢運算式語法」真的超級好用,例如做join五個table時我就習慣用「查詢運算式語法」,因為可以直接將SSMS(SQL Server Management Studio)產生的SQL直接改寫成linq,如果用方法或函式的方式,說真的我還不會寫勒XD
另外39行最後的ToList()的使用,是因為Where()會回傳一個IQueryable型別的物件,會將Linq組成T-SQL,當此行程式碼被執行時才會去資料庫執行query撈取資料
提供三種載入模式
觀察Day23專案的資料模型,可以看到一個使用者可以有多筆Email,建立關聯之後(中間的虛線),User實體下就會出現Email的導覽屬性
使用延遲式載入寫改昨天的程式碼,使用方式非常簡單,透過User物件去存取Email這個導覽屬性就能直接去資料庫取得資料,而取得資料的時機就是40行存取Email這個導覽屬性的時候,所以下圖這個Action 總共跟資料庫溝通了兩次:
第一次是31行取得User資料的時候
第二次是40行取得導覽屬性Email的時候
如果想要減少資料庫的溝通,是否可以在取得User資料時就將Email也載入呢,就是使用接下來的積極式載入
使用Include方法,並搭配SingleOrDefult回傳一筆資料,若找不到而回傳null,沒有搭配之前Find()方法是因為Find是屬於DbSet的方法無法與Include搭配。改寫如下圖32行,那麼此Action只會與資料庫連線一次就把所需要的資料通通取回來囉!而以方法為「基礎的查詢語法」與「查詢運算式語法」可以搭配使用,請參考下圖的寫法2
寫法如下圖,第一次透過資料庫取得User資料,在34行時透過Load()將導覽屬性的資料載入,這跟延遲式載入沒有什麼差別
記得先把lazyloading關閉,db.Configuration.LazyLoadingEnabled = false;,並透過Entry方法與Collection將導覽屬性載入
但如果我只想先載入兩筆資料,就可以透過明確式載入告訴資料庫要如何載入導覽屬性的資料,例如下圖34行宣告了一個IQueryable型別的變數,等到第41行才會去資料庫執行取資料的動作,如果今天Email有100筆,也只會取回2筆,但是如果透過延遲式或積極式載入可是會直接將100筆直接載回來的喔!有點浪費XD
如果想觀察linq與資料庫的連線可以使用Sql Profiler來監看linq的執行,不過這功能只有SQL Server Standard才有,我只有Express版就不示範了XD
下載今日專案:https://github.com/juben-wang/MvcApplication28